package servicebase

import (
	"github.com/eclipse/paho.mqtt.golang"
	"github.com/pkg/errors"
	"jkgo/jk/jklog"
	"strconv"
	"time"
)

type SSIoTClient struct {
	IsConnected bool
	Addr        string
	Port        int
	Id          string
	Url         string

	Opts   *mqtt.ClientOptions
	Client mqtt.Client

	mh MsgHandle
}

func NewSSIoTClient(addr string, port int, id string) (*SSIoTClient, error) {
	ss := &SSIoTClient{
		Addr: addr,
		Port: port,
		Id:   id,
	}
	ss.Opts = mqtt.NewClientOptions()
	broker := "tcp://" + ss.Addr + ":" + strconv.Itoa(ss.Port)
	ss.Opts.AddBroker(broker)
	ss.Opts.SetClientID(id)
	ss.Opts.SetUsername("")
	ss.Opts.SetPassword("")
	ss.Opts.SetCleanSession(false)
	ss.Opts.SetDefaultPublishHandler(ss.OnRecv)
	ss.Opts.SetConnectionLostHandler(ss.OnDisconnected)

	ss.Client = mqtt.NewClient(ss.Opts)
	return ss, nil
}

func (ss *SSIoTClient) Close() {
	ss.Client.Disconnect(250)
}

func (ss *SSIoTClient) SetMsgHandle(mh MsgHandle) {
	ss.mh = mh
}

func (ss *SSIoTClient) Connect() {
	for {
		if !ss.IsConnected {
			token := ss.Client.Connect()
			token.Wait()
			if token.Error() != nil {
				jklog.L().Errorln("connect error ", token.Error())
				time.Sleep(time.Second * 4)
				continue
			}
			ss.IsConnected = true
			ss.Sub("/" + ss.Id)
			ss.mh.IoTStatusReport("connected")
		}
		time.Sleep(time.Second * 2)
	}
}

func (ss *SSIoTClient) Pub(topic string, payload string) error {
	if !ss.IsConnected {
		return errors.New("not connected")
	}
	token := ss.Client.Publish(topic, 0, false, payload)
	token.Wait()
	return token.Error()
}

func (ss *SSIoTClient) Sub(topic ...string) error {
	if !ss.IsConnected {
		return errors.New("client not connected")
	}

	for _, u := range topic {
		token := ss.Client.Subscribe(u, 0, nil)
		token.Wait()
		if token.Error() != nil {
			jklog.L().Errorln("sub topic ", u, " error ", token.Error())
		}
	}
	return nil
}

func (ss *SSIoTClient) OnRecv(client mqtt.Client, msg mqtt.Message) {
	jklog.L().Debugln("on recv ", msg.Topic(), ", pay load len ", len(string(msg.Payload())))
	paylen := 100
	if len(string(msg.Payload())) < paylen {
		jklog.L().Debugln("payload ", string(msg.Payload()))
	} else {
		jklog.L().Debugln("payload ", string(msg.Payload())[:paylen])
	}
	if ss.mh != nil {
		err := ss.mh.IoTDealMessage(msg.Topic(), string(msg.Payload()))
		if err != nil {
			jklog.L().Errorln("handle message error ", err)
		}
	}
}

func (ss *SSIoTClient) OnDisconnected(client mqtt.Client, err error) {
	jklog.L().Warnln("on disconnected from broker ", err)
	ss.IsConnected = false
}

func (ss *SSIoTClient) Recv() {
	jklog.L().Warnln("unimplemented as unuse")
}
